#include <Keyboard.h>
#include <EEPROM.h>
#include <keyboard_matrix.h>
#include <vim_mod.h>
#include <basic.h>

static bool _main_kb_is_pressed[KB_ROWS][KB_COLUMNS];
bool (*main_kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_is_pressed;

static bool _main_kb_was_pressed[KB_ROWS][KB_COLUMNS];
bool (*main_kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_was_pressed;

uint8_t main_layers_pressed[KB_ROWS][KB_COLUMNS];

uint8_t main_loop_row;
uint8_t main_loop_col;

uint8_t main_arg_layer;
bool main_arg_is_pressed;
bool main_arg_was_pressed;

/* 函数回调 */
#ifndef kb_layout_press_get
extern const void_funptr_t
    _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS];

#define kb_layout_press_get(layer, row, column) \
  ((void_funptr_t)(&(_kb_layout_press[layer][row][column]))) /*返回void(*)(void)类型的函数指针*/
#endif

void main_exec_key(void)
{
  /* 在调用过程中，即layer #undef前，layer默认是0，后续有待扩展 */
  void (*key_function)(void) = kb_layout_press_get(layer, row, col);

  if (key_function)
    (*key_function)();
}

uint8_t main_layers_peek(uint8_t offset)
{
  return 0; // default, or error
}

/* 宏定义的细节

（1）对于有参数的宏定义，宏定义时，在宏名与带参数的括号之间不应加空格，否则将空格以后的字符都作为替代字符串的一部分。

（2）带参数的宏定义只是进行简单的字符替换，宏展开则是在编译前进行的，在展开时并不分配内存单元，不进行值得传递处理，因此替换不会占用运行时间，只占用编译时间
————————————————
版权声明：本文为CSDN博主「Hugo_yanghui」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/yhhdll0107/article/details/105194135
*/

#define update_matrix_from_pin(matrix) \
  do                                   \
  {                                    \
    /* read and update matrix */       \
    matrix[0][0] = !digitalRead(2);    \
    matrix[0][1] = !digitalRead(3);    \
    matrix[0][2] = !digitalRead(4);    \
    matrix[1][0] = !digitalRead(5);    \
    matrix[1][1] = !digitalRead(6);    \
    matrix[1][2] = !digitalRead(7);    \
    matrix[2][0] = !digitalRead(8);    \
    matrix[2][1] = !digitalRead(9);    \
    matrix[2][2] = !digitalRead(10);   \
  }
while (0)

  uint8_t teensy_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS])
  {
    update_matrix_from_pin(matrix);
    return 0; // success
  }

/* returns
 * - success: 0
 * - error: number of the function that failed
 */
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS])
{
  if (update_matrix(matrix))
    return 1;

  return 0; // success
}

void setup()
{
  for (int i = 2; i < 11; i++)
  { //设置2-11引脚为INPUT
    pinMode(i, INPUT_PULLUP);
  }
  Keyboard.begin(); //开始键盘通信
}

void loop()
{

  for (;;)
  {
    // swap `main_kb_is_pressed` and `main_kb_was_pressed`, then update
    bool(*temp)[KB_ROWS][KB_COLUMNS] = main_kb_was_pressed;
    main_kb_was_pressed = main_kb_is_pressed;
    main_kb_is_pressed = temp;

    kb_update_matrix(*main_kb_is_pressed);

#define row main_loop_row
#define col main_loop_col
#define layer main_arg_layer
#define is_pressed main_arg_is_pressed
#define was_pressed main_arg_was_pressed

    for (row = 0; row < KB_ROWS; row++)
    {

      for (col = 0; col < KB_COLUMNS; col++)
      {

        is_pressed = (*main_kb_is_pressed)[row][col];
        was_pressed = (*main_kb_was_pressed)[row][col];

        /*对于每一个按键而言，如果该按键上一次的物理状态和这一次的物理状态不同，则更新按键键值，否则说明，该按键连续按下，沿用之前的键值*/
        if (is_pressed != was_pressed)
        {
          /* 按下触发，下降沿 */
          if (is_pressed)
          {
            layer = main_layers_peek(0);           /* 默认使用第0层，有待优化 */
            main_layers_pressed[row][col] = layer; /* 本次按下所在的层 */
          }
          main_exec_key();
          /*这里让定义失效，防止和其它地方的定义冲突*/
        }

#undef row
#undef col
#undef layer
#undef is_pressed
#undef was_pressed
      }
    }
    delay(DEBOUNCE_TIME);
  }
}
/*快捷组合按键
if(digitalRead(10) == 1){  //按下小键盘中的3
    Keyboard.press(KEY_RIGHT_CTRL);
    Keyboard.press('v');
    delay(300);
    Keyboard.releaseAll();
  }
  */

/*按单独按键
 if(digitalRead(7) == 1){  //按下小键盘中的6
    Keyboard.press('z');
  }else{
    Keyboard.release('z');
  }
  */

/*键盘按键定义
键盘左边ctrl    ---   KEY_LEFT_CTRL
键盘左边shift   ---   KEY_LEFT_SHIFT  
键盘左边alt     ---   KEY_LEFT_ALT
键盘左边win     ---   KEY_LEFT_GUI  
键盘右边ctrl    ---   KEY_RIGHT_CTRL
键盘右边shift   ---   KEY_RIGHT_SHIFT
键盘右边alt     ---   KEY_RIGHT_ALT
键盘右边win     ---   KEY_RIGHT_GUI
方向键上        ---   KEY_UP_ARROW
方向键下        ---   KEY_DOWN_ARROW
方向键左        ---   KEY_LEFT_ARROW
方向键右        ---   KEY_RIGHT_ARROW
删除键          ---   KEY_BACKSPACE
tab键           ---   KEY_TAB
回车键          ---   KEY_RETURN
esc键           ---   KEY_ESC
insert键        ---   KEY_INSERT
delete键        ---   KEY_DELETE
page up键       ---   KEY_PAGE_UP 
page down键     ---   KEY_PAGE_DOWN
home键          ---   KEY_HOME
end键           ---   KEY_END
capslock键      ---   KEY_CAPS_LOCK 
空格键           ---  ' '
F1              ---   KEY_F1
F2              ---   KEY_F2
F3              ---   KEY_F3
F4              ---   KEY_F4
F5              ---   KEY_F5
F6              ---   KEY_F6
F7              ---   KEY_F7
F8              ---   KEY_F8
F9              ---   KEY_F9
F10             ---   KEY_F10
F11             ---   KEY_F11
F12             ---   KEY_F12
*/

/*虚拟键盘常用函数
Keyboard.begin();              ---     开始键盘（USB）通信
Keyboard.end();                ---     结束键盘（USB）通信
Keyboard.press(x);             ---     按下为x的键 x可为 char（ASCII）
Keyboard.release(x);           ---     松开（释放）为x的键 x可为 char（ASCII）
Keyboard.releaseAll();         ---     松开（释放）所有按下的键
Keyboard.print(x);              ---    输入为x的内容 x可为 String
Keyboard.println(x);            ---    输入为x的内容并换行 x可为 String
*/
